package com.ds.common.wx;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.ds.common.redis.RedisService;
import com.ds.common.route.config.CorporationConfig;
import com.ds.common.route.context.RuntimeClient;
import com.thrk.cm.common.QxUrl;
import com.thrk.cm.common.RedisKeys;
import com.thrk.cm.common.WXCode;
import com.thrk.cm.common.WXUrl;
import com.thrk.cm.pojo.qixin.TokenResponse;
import com.thrk.cm.pojo.response.RkH5AccessTokenResp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Map;
@Service
@ConditionalOnProperty(
        prefix = "ds.token",
        name = {"enabled"},
        havingValue = "true",
        matchIfMissing = false
)
@Slf4j
public class TokenService {

    RestTemplate restTemplate;
    RedisService redisService;

    @Autowired
    public TokenService(RestTemplate restTemplate, RedisService redisService){
        this.redisService = redisService;
        this.restTemplate = restTemplate;
    }


    private final static int ACCESS_TOKEN_EXPIRED_SECONDS = 1800;


    public String getAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getToken(corporationConfig.getWeibanCorpId(),corporationConfig.getWeibanSecret(), WXUrl.ACCESS_TOKEN, true);
    }


    public String getAccessTokenAndroidLogin() {
        return getQxToken(RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig().getQxAndroidLoginSecret());
    }


    public String getUserInfo(String code) {
        String accessToken = getAccessTokenAndroidLogin();
        String url = String.format(QxUrl.GET_USER_INFO, accessToken, code);
        String rt = restTemplate.getForObject(url, String.class);
        JSONObject resultObj = JSON.parseObject(rt);
        log.info("get user info by qxCode:{},rt:{}", code, resultObj.toString());
        if (resultObj.get("errcode").equals(0)) {
            return resultObj.get("UserId").toString();
        } else {
            log.error("get userinfo fail,code:{}", code);
            return "";
        }
    }


    public String getWxmpThrkAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getWxGzhToken(corporationConfig.getGzhAppId(), corporationConfig.getGzhSecret());
    }


    public String getWxmpRkgjAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getWxGzhToken(corporationConfig.getGzhGuojiAppId(), corporationConfig.getGzhGuojiSecret());
    }


    public String getNoticeAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxToken(corporationConfig.getWxNoticeSecret());
    }


    public String getWarehouseAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxToken(corporationConfig.getWarehouseSecret());
    }

    /**
     * 获取天合人康公众号的JS 接口的临时票据
     *
     * @return
     */

    public String getWxmpThrk_jsapi_ticket() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return  getWxGzhJsTicket(corporationConfig.getGzhAppId(), corporationConfig.getGzhSecret());
    }


    public String getContactToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxTokenNoCache(corporationConfig.getContactSecret());
    }

    private String getPeriodicEvaluationAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxToken(corporationConfig.getQxpeSecret());
    }


    public String getPeriodicEvaluationUserInfo(String code) {
        String accessToken = getPeriodicEvaluationAccessToken();
        log.info("getPeriodicEvaluationUserInfo:{}/{}", accessToken, code);
        String url = String.format(QxUrl.GET_USER_INFO, accessToken, code);
        String rt = restTemplate.getForObject(url, String.class);
        JSONObject resultObj = JSON.parseObject(rt);
        log.info("get user info by qxCode:{},rt:{}", code, resultObj.toString());
        if (resultObj.get("errcode").equals(0)) {
            return resultObj.get("UserId").toString();
        } else {
            log.error("get userinfo fail,code:{}", code);
            return "";
        }
    }


    public String getApproveToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxTokenNoCache(corporationConfig.getApprovalSecret());
    }


    public String getWorkWXAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxToken(corporationConfig.getQxSecret());
    }


    public String getRkSmallAppAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        String redisKey = "rk_small_app_access_token@" +corporationConfig.getMiniAppId();
        String accessToken = redisService.get(redisKey);
        if (StringUtils.isNotEmpty(accessToken)) {
            return accessToken;
        }
        String path = "https://api.weixin.qq.com/cgi-bin/stable_token";
        Map<String, String> body = ImmutableMap.of("grant_type","client_credential",
                "appid",corporationConfig.getMiniAppId(),
                "secret",corporationConfig.getMiniAppSecret());
        JSONObject ret = restTemplate.postForObject(path, body, JSONObject.class);
        log.info("get rkkt xcx accessToken from api:{}", JSON.toJSONString(ret));
        if(null != ret){
            accessToken = ret.getString("access_token");
            if(StringUtils.isNotEmpty(accessToken)) {
                redisService.set(redisKey, ret.getString("access_token"));
                redisService.expire(redisKey, ret.getInteger("expires_in") - 100);
                return ret.getString("access_token");
            }
        }
        throw new RuntimeException("获取access_token失败，请检查人康课堂小程序参数设置");
    }


    public RkH5AccessTokenResp getRkH5AccessToken(String code) {

        RkH5AccessTokenResp rkH5AccessTokenResp;
        String redisKey = RedisKeys.RK_H5_ACCESS_TOKEN_PREFIX + "@" +code;
        String result = redisService.get(redisKey);
        rkH5AccessTokenResp = convertToRkH5AccessToken(result);
        if (rkH5AccessTokenResp != null){
            return rkH5AccessTokenResp;
        }
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        String url = String.format(QxUrl.GET_RK_H5_ACCESSTOKEN, corporationConfig.getH5AppId(), corporationConfig.getH5Secret(), code);
        result = restTemplate.getForObject(url, String.class);
        log.info("get rkH5 accessToken from wx,url:{}, {}", url, result);
        rkH5AccessTokenResp = convertToRkH5AccessToken(result);
        if (rkH5AccessTokenResp!=null) {
            redisService.set(redisKey, result);
            redisService.expire(redisKey, ACCESS_TOKEN_EXPIRED_SECONDS);
            return rkH5AccessTokenResp;
        } else {
            log.error("getRkH5AccessToken fail:" + result);
            throw new RuntimeException("获取access_token失败，请检查人康H5参数设置");
        }
    }

    private RkH5AccessTokenResp convertToRkH5AccessToken(String result){
        if(StringUtils.isNotEmpty(result)) {
            RkH5AccessTokenResp rkH5AccessTokenResp = new RkH5AccessTokenResp();
            JSONObject resultObj = JSON.parseObject(result);
            String accessToken = resultObj.getString("access_token");
            if (StringUtils.isNotEmpty(accessToken)) {
                rkH5AccessTokenResp.setAccessToken(accessToken);
                rkH5AccessTokenResp.setOpenid(resultObj.get("openid").toString());
                rkH5AccessTokenResp.setUnionid(resultObj.get("unionid").toString());
                return rkH5AccessTokenResp;
            }
        }
        return null;
    }


    public String getImportantMsgToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxTokenNoCache(corporationConfig.getImportantNoticeSecret());
    }


    public String getQYLiveAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxToken(corporationConfig.getQxLiveSecret());
    }



    public String getQYHbAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxToken(corporationConfig.getQxRedPackageSecret());
    }



    public String getQYCusgAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxToken(corporationConfig.getQxTagSecret());
    }


    public String getHbTestAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxToken(corporationConfig.getQxRedPackageTestSecret());
    }


    public String getQyManageAccessToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxToken(corporationConfig.getWxManageSecret());
    }


    public String getWxAppToken(String code) {
        String result = HttpUtil.get("https://api.weixin.qq.com/sns/oauth2/access_token?appid=wxea3d7a0f5abd4899&secret=5c3fe549007bb2ac71d4b1345e68eeeb&code=" + code + "&grant_type=authorization_code");
        JSONObject resultObj = JSON.parseObject(result);
        log.info("token response :{}", resultObj.toString());
        return resultObj.toString();
    }



    public String getRechargeMsgToken() {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getQxTokenNoCache(corporationConfig.getRechargeSecret());
    }


    private String getQxToken(String secret) {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getToken(corporationConfig.getQxCorpId(),secret,WXUrl.GET_TOKEN,true);
    }

    private String getQxTokenNoCache(String secret) {
        CorporationConfig corporationConfig = RuntimeClient.getRuntimeContext().getAgentConfig().getCorporationConfig();
        return getToken(corporationConfig.getQxCorpId(),secret,WXUrl.GET_TOKEN,false);
    }

    private String getToken(String corpId,String secret,String api, boolean isUseCache) {
        String redisKey = corpId +"@"+ secret;
        if(isUseCache){
            String value = redisService.get(redisKey);
            if(value != null){
                return value;
            }
        }

        Map<String, String> param = Maps.newHashMap();
        param.put("corpid",corpId);
        param.put("corpsecret", secret);
        TokenResponse response = restTemplate.postForObject(api, param, TokenResponse.class);
        if (response != null && WXCode.OK == response.getErrcode()) {
            if(isUseCache) {
                redisService.set(redisKey, response.getAccess_token());
                redisService.expire(redisKey, ACCESS_TOKEN_EXPIRED_SECONDS);
            }
            return response.getAccess_token();
        } else {
            log.error("getToken response:{},secret:{}", response,secret);
            throw new RuntimeException("获取access_token失败");
        }
    }
    /**
     * 获取微信公号号的token
     *
     * @param appId
     * @param appSecret
     * @return
     */
    private String getWxGzhToken(String appId, String appSecret) {

        String redisKey = RedisKeys.wxmp_token + "@" + appId + "@" + appSecret;
        String value = redisService.get(redisKey);
        if (value != null) {
            return value;
        }
        String url = String.format(WXUrl.WX_GZH_TOKEN, appId, appSecret);
        String result = HttpUtil.get(url);
        JSONObject resultObj = JSON.parseObject(result);
        log.info("获取微信token--->{}", resultObj.toString());
        if (resultObj.containsKey("access_token")) {
            String token = resultObj.getString("access_token");
            redisService.set(redisKey, token);
            redisService.expire(redisKey, resultObj.getInteger("expires_in"));

            return token;
        }
        log.error("获取微信token--->{}", resultObj.toString());

        return null;
    }

    /**
     * 获取微信公号号JS接口的临时票据
     *
     * @param appId
     * @return
     */
    private String getWxGzhJsTicket(String appId, String appSecret) {

        String redisKey = RedisKeys.wxmp_js_ticket + "@"+appId+"@"+appSecret;
        String value = redisService.get(redisKey);
        if (value != null) {
            return value;
        }

        String token = getWxGzhToken(appId, appSecret);
        if (token == null) {
            log.error("获取微信公众号token错误{}", appId);
            return null;
        }
        String url = String.format(WXUrl.WX_GZH_JS_TOKEN, token);
        String result = HttpUtil.get(url);
        JSONObject resultObj = JSON.parseObject(result);

        log.debug("获取微信jsapi_ticket--->{}", resultObj.toString());
        if (resultObj.containsKey("ticket")) {
            String jsticket = resultObj.getString("ticket");
            redisService.set(redisKey, jsticket);
            redisService.expire(redisKey, resultObj.getInteger("expires_in"));
            return jsticket;
        }
        log.error("获取微信jsapi_ticket--->{}", resultObj.toString());
        return null;
    }
}
